import { createWhere, createOrder, createPartial, createMap, createGroup } from './tool'
import { isGroupResult } from './is'
import { cloneDeep } from 'lodash-es'

// 数据库对象类
export default class Entity {
  // 构造函数
  constructor (data) {
    this._data = data // 数据列表
    this._pipeline = [] // 指令流水线
  }

  where (predicate) {
    // 将 where 指令加入流水线中
    this._pipeline.push(createWhere(predicate))
    return this
  }

  order (predicate) {
    // 将 order 指令加入流水线中
    this._pipeline.push(createOrder(predicate))
    return this
  }

  partial (limit = 10, offset = 0) {
    // 将 partial 指令加入流水线中
    this._pipeline.push(createPartial(limit, offset))
    return this
  }

  // 使用 map 时需保留 group update delete 用到的 key 值
  map (predicate) {
    // 将 map 指令加入流水线中
    this._pipeline.push(createMap(predicate))
    return this
  }

  group (predicate) {
    // 将 group 指令加入流水线中
    this._pipeline.push(createGroup(predicate))
    return this
  }

  value () {
    return this._execute()
  }

  count () {
    const data = this._execute()
    const length = data.length
    // 没执行 group 指令的情况下直接返回数组长度
    if (length === 0 || !isGroupResult(data[0])) return length
    // 执行 group 指令的情况下，返回每个分类的数组长度
    return (data).map(item => {
      return {
        value: item.value,
        count: item.items.length
      }
    })
  }

  update (predicate, key = 'id') {
    const data = this._execute()
    data.forEach(item => {
      const index = this._data.findIndex(originItem => originItem[key] === item[key])
      this._data.splice(index, 1, predicate(this._data[index]))
    })
    return this._data
  }

  delete (key = 'id') {
    const data = this._execute()
    data.forEach(item => {
      const index = this._data.findIndex(originItem => originItem[key] === item[key])
      this._data.splice(index, 1)
    })
    return this._data
  }

  setPipeline (pipeline) {
    this._pipeline = pipeline
    return this
  }

  _execute () {
    let data = cloneDeep(this._data)
    // 依次执行流水线中的指令
    this._pipeline.forEach(command => {
      data = command(data)
    })
    return data
  }
}

export function from (data) {
  return new Entity(data)
}
